﻿#include "UdpBroadcast.h"
#include <QDebug>
#include "jsoncpp-1.9.1/json/json.h"

UdpBroadcast *UdpBroadcast::Singleton()
{
	static UdpBroadcast * singleton = new UdpBroadcast();
	return singleton;
}

UdpBroadcast::UdpBroadcast(QObject *parent) : QObject(parent)
{
	pudpClientSocket = new QUdpSocket();
	QUdpSocket::connect(pudpClientSocket, &QUdpSocket::readyRead, this, &UdpBroadcast::slotClientReadyRead);
}

UdpBroadcast::~UdpBroadcast()
{
	if (pudpClientSocket)
	{
		delete pudpClientSocket;
		pudpClientSocket = nullptr;
	}
	this->pudpServerSocketVec.clear();
}

bool UdpBroadcast::InitClient(QVector<quint16> serverPortVec)
{
	this->clientServerPortVec = serverPortVec;
	return true;
}

bool UdpBroadcast::InitServer(QString serverName, QString serverAddr, QVector<quint16> serverPort)
{
	this->serverPortVec = serverPort;
	this->serverName = serverName;
	this->serverAddr = serverAddr;
	this->pudpServerSocketVec.clear();

	for (int i = 0; i < this->serverPortVec.size(); ++i)
	{
		QSharedPointer<QUdpSocket> pSocket(new QUdpSocket());
		QUdpSocket::connect(pSocket.get(), &QUdpSocket::readyRead, this, &UdpBroadcast::slotServerReadyRead);
		if (!pSocket->bind(this->serverPortVec[i], QUdpSocket::ShareAddress))
		{
			continue;
		}
		this->pudpServerSocketVec.append(pSocket);
		return true;
	}
	qDebug() << "InitServer failed. " << serverName << ", " << serverAddr << ", " << serverPort;
	return false;
}

void UdpBroadcast::scan()
{
	QByteArray datagram = "helloWebServer";
	for (auto it : this->clientServerPortVec)
	{
		pudpClientSocket->writeDatagram(datagram, QHostAddress::Broadcast, it);
	}
}

void UdpBroadcast::slotClientReadyRead()
{
	if (!pudpClientSocket)
	{
		return;
	}
	while (pudpClientSocket->hasPendingDatagrams())
	{
		QHostAddress peerAddress;
		quint16 peerPort = 0;
		QString peerName;

		QByteArray datagram;
		datagram.resize(int(pudpClientSocket->pendingDatagramSize()));
		pudpClientSocket->readDatagram(datagram.data(), datagram.size(), &peerAddress, &peerPort);
		/*
			qDebug() << "peerName:" << peerName
					 << ", peerAddress:" << peerAddress
					 << ", peerPort:" << peerPort
					 << " ### " << "Received datagram: " << datagram.constData();
		*/

		/*QHostInfo::lookupHost(peerAddress.toString(), [](QHostInfo info) {
				qDebug() << "lookupHost::peerName:" << info.hostName()
							<< ", peerAddress:" << info.addresses()
							;
			});*/


		std::string strMsgUtf8 = datagram.toStdString();
		Json::Value root;
#if 1
		Json::CharReaderBuilder rbuilder;
		std::unique_ptr<Json::CharReader> const reader(rbuilder.newCharReader());
		std::string errs;
		if (!reader->parse(strMsgUtf8.data(), strMsgUtf8.data() + strMsgUtf8.size(), &root, &errs))
		{// json解析
			qDebug() << "json parse failed. json:" << datagram;
			return;
		}
#else
		Json::Reader reader;
		if (!reader.parse(strMsgUtf8, root))
		{// json解析
			qDebug() << "json parse failed. json:" << datagram;
			return;
		}
#endif
		auto funcGetJsonString = [](Json::Value& node, const std::string strNodeName, QString& strVal)->bool {
			if (!node.isMember(strNodeName))
			{
				qDebug() << tr("json %1 isn't exist").arg(QString::fromStdString(strNodeName));
				return false;
			}
			if (node[strNodeName].isNull())
			{
				qDebug() << tr("json %1 isn't exist").arg(QString::fromStdString(strNodeName));
				return false;
			}
			if (!node[strNodeName].isString())
			{
				qDebug() << tr("json %1 isn't string value").arg(QString::fromStdString(strNodeName));
				return false;
			}
			strVal = QString::fromUtf8(node[strNodeName].asString().c_str());
			return true;
		};

		QString serverName;
		if (!funcGetJsonString(root, "serverName", serverName))
		{
			continue;
		}

		QString serverAddr;
		if (!funcGetJsonString(root, "serverAddr", serverAddr))
		{
			continue;
		}

		// 发送信号
		signalNewServer(serverName, serverAddr);

	}
}

void UdpBroadcast::slotServerReadyRead()
{
	QUdpSocket * pudpServerSocket = qobject_cast<QUdpSocket *>(sender());
	if (!pudpServerSocket)
	{
		qDebug() << "slotServerReadyRead():pudpServerSocket is null";
		return;
	}
	while (pudpServerSocket->hasPendingDatagrams())
	{
		QHostAddress peerAddress;
		quint16 peerPort = 0;
		//QString peerName;

		/*QString localDomainName = QHostInfo::localDomainName();
					QString localHostName = QHostInfo::localHostName();
					qDebug() << "localDomainName:" << localDomainName
						<< ", localHostName:" << localHostName
						;*/
						/*QHostInfo::lookupHost(peerAddress.toString(), [](QHostInfo info) {
										qDebug() << "lookupHost::peerName:" << info.hostName();
									});*/

		QByteArray datagram;
		datagram.resize(int(pudpServerSocket->pendingDatagramSize()));
		pudpServerSocket->readDatagram(datagram.data(), datagram.size(), &peerAddress, &peerPort);

		/*qDebug() << "peerName:" << peerName
						<< ", peerAddress:" << peerAddress
						<< ", peerPort:" << peerPort
						<< " ### " << tr("Received datagram: ***%1***").arg(datagram.constData());*/



		if (QString::fromUtf8(datagram) == "helloWebServer")
		{// 返回数据

			Json::Value root;
			root["serverName"] = serverName.toUtf8().toStdString();
			root["serverAddr"] = serverAddr.toUtf8().toStdString();

			Json::StreamWriterBuilder wbuilder;
			//wbuilder["commentStyle"] = "None";
			wbuilder["indentation"] = "";
			std::string document = Json::writeString(wbuilder, root);
			qDebug() << QString::fromStdString(document);
			pudpServerSocket->writeDatagram(document.data(), static_cast<qint64>(document.size()), peerAddress, peerPort);

			//QString strSendData = tr("{\"serverName\":\"%1\", \"serverAddr\":\"%2\"}").arg(serverName).arg(serverAddr);
			//QByteArray sendDataBytes = strSendData.toUtf8();
			//pudpServerSocket->writeDatagram(sendDataBytes, peerAddress, peerPort);
		}
	}
}




